package com.gmrz.webauthn.handler;

import com.gmrz.service.challengestore.ChallengeStoreService;
import com.gmrz.uaf.common.Constants;
import com.gmrz.uaf.common.GuiceUtil;
import com.gmrz.uaf.protocol.v1.json.UAFSchemaBuilder;
import com.gmrz.uaf.protocol.v1.processor.UAFDeregisterProcessor;
import com.gmrz.uaf.protocol.v1.schema.DeregisterAuthenticator;
import com.gmrz.uaf.protocol.v1.schema.DeregisterationRequest;
import com.gmrz.uaf.server.ServerContext;
import com.gmrz.uaf.servlet.v1.handler.UAFBaseHandler;
import com.gmrz.uaf.servlet.v1.request.DeregContext;
import com.gmrz.uaf.servlet.v1.request.ReceiveReqPayload;
import com.gmrz.uaf.servlet.v1.response.FidoRespPayload;
import com.gmrz.uaf.servlet.v1.validation.PayloadValidationException;
import com.gmrz.uaf.servlet.v1.validation.RestValidator;
import com.gmrz.util.Convert;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.lang.reflect.Type;
import java.util.Collections;
import java.util.List;

public class WebDeregRequestHandler extends UAFBaseHandler {
    private static final Logger LOG = LogManager.getLogger(WebDeregRequestHandler.class);

    public String delete(String request) {
        LOG.info("[/reg/delete][begin]");
        ServerContext.getServerContext().getFidoLog().setRequest(request);
        Gson gson = UAFSchemaBuilder.getGson();
        FidoRespPayload<String> respPayload = new FidoRespPayload<String>();
        Type reqType = new TypeToken<ReceiveReqPayload<DeregContext>>() {
        }.getType();

        String response = null;
        ReceiveReqPayload<DeregContext<String>> reqPayload = null;
        String userName = null;
        try {
            reqPayload = gson.fromJson(request, reqType);
            logRequest(request, reqPayload.getContext().getTransNo(), reqPayload.getContext().getUserName(),
                    reqPayload.getContext().getAppID(), reqPayload.getContext().getAuthType(), reqPayload.getContext().getTransType(), Constants.Method.DEREG_ONE);
            validate(reqPayload);

            UAFDeregisterProcessor deregisterProcessor = GuiceUtil.getProcessorInjector()
                    .getInstance(UAFDeregisterProcessor.class);

            DeregContext<String> context = reqPayload.getContext();
            userName = generateHashedUserName(context.getUserName(), context.getRf1(), context.getRf2());

            DeregisterationRequest requests = deregisterProcessor.deleteOne(userName, context.getAppID(),
                    context.getDeviceID(), context.getAuthType(), context.getTransType(), context.getFrom(),null);
            List deregisterationRequests = Collections.singletonList(requests);

            response = buildReceiveResponse(gson, respPayload, deregisterationRequests);
            try {
                delCache(context.getAppID(), context.getDeviceID(), userName, context.getAuthType(), context.getTransType());
            }catch (Exception e){

            }
            ChallengeStoreService challengeStoreService = GuiceUtil.getProcessorInjector().getInstance(ChallengeStoreService.class);
            if(null != requests && null != requests.getDeregisterAuthenticators()) {
                for(DeregisterAuthenticator deregisterAuthenticator : requests.getDeregisterAuthenticators()) {
                    String authErrorCountKey = Constants.AUTH_ERROR_COUNT + Convert.toBase64(deregisterAuthenticator.getKeyID().getId())+"."+ context.getAuthType() + "." + context.getTransType() + "." + userName;
                    challengeStoreService.deleteRedisValue(authErrorCountKey);
                }
            }
        } catch (Exception ex) {
            LOG.error(ex);
            response = buildFidoRespFromException(respPayload, ex);
        }
        LOG.info("[/reg/delete][end]");
        return response;
    }

    private void validate(ReceiveReqPayload<DeregContext<String>> reqPayload) throws PayloadValidationException {
        if ((reqPayload == null) || (reqPayload.getContext() == null)) {
            throw new PayloadValidationException("context", RestValidator.VALIDATION_ERROR.EMPTY);
        }
        DeregContext<String> context = reqPayload.getContext();
        RestValidator.validate("userName", context.getUserName());
        RestValidator.validate("appID", context.getAppID());
        RestValidator.validate("deviceID", context.getDeviceID());
        RestValidator.validate("authType", context.getAuthType());
        RestValidator.validate("transType", context.getTransType());
        RestValidator.validate("transNo", context.getTransNo());
        RestValidator.validate("rf1", context.getRf1());
        RestValidator.validate("rf2", context.getRf2());
        RestValidator.validate("from", context.getFrom());
    }

}
